home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / alpha.arc / NR3.C < prev    next >
C/C++ Source or Header  |  1988-07-26  |  23KB  |  840 lines

  1. /* net/rom level 3 low level processing
  2.  * Dan Frank, W9NK
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include "global.h"
  7. #include "mbuf.h"
  8. #include "iface.h"
  9. #include "timer.h"
  10. #include "arp.h"
  11. #include "slip.h"
  12. #include "ax25.h"
  13. #include "netrom.h"
  14. #include "lapb.h"
  15. #include <ctype.h>
  16.  
  17. /* Nodes message broadcast address: "NODES" in shifted ASCII */
  18. struct ax25_addr nr_nodebc = {
  19.     'N'<<1, 'O'<<1, 'D'<<1, 'E'<<1, 'S'<<1, ' '<<1,
  20.     ('0'<<1) | E
  21. } ;
  22.  
  23. struct nriface nrifaces[NRNUMIFACE] ;
  24. unsigned nr_numiface ;
  25. struct nrnbr_tab *nrnbr_tab[NRNUMCHAINS] ;
  26. struct nrroute_tab *nrroute_tab[NRNUMCHAINS] ;
  27. struct nrnf_tab *nrnf_tab[NRNUMCHAINS] ;
  28. unsigned nr_nfmode = NRNF_NOFILTER ;
  29. unsigned nr_ttl = 64 ;
  30. unsigned obso_init = 6 ;
  31. unsigned obso_minbc = 5 ;
  32. unsigned nr_maxroutes = 5 ;
  33. unsigned nr_autofloor = 1 ;
  34. struct interface *nr_interface ;
  35.  
  36. /* send IP datagrams across a net/rom network connection */
  37. int
  38. nr_send(bp,interface,gateway,precedence,delay,throughput,reliability)
  39. struct mbuf *bp ;
  40. struct interface *interface ;
  41. int32 gateway ;
  42. char precedence ;
  43. char delay ;
  44. char throughput ;
  45. char reliability ;
  46. {
  47.     struct ax25_addr dest ;
  48.     struct mbuf *tbp, *htonnr3() ;
  49.     struct nr3hdr n3hdr ;
  50.     char *hwaddr ;
  51.     struct arp_tab *arp ;
  52.  
  53.     if ((arp = arp_lookup(ARP_NETROM,gateway)) == NULLARP) {
  54.         free_p(bp) ;    /* drop the packet if no route */
  55.         return ;
  56.     }
  57.     hwaddr = arp->hw_addr ;                /* points to destination */
  58.     memcpy(dest.call, hwaddr, ALEN) ;
  59.     dest.ssid = hwaddr[ALEN] ;
  60.         
  61.     /* set up host format header */
  62.     /* The null source call is a signal to nr_route to insert the call */
  63.     /* of the outbound interface.  We can't do it here because */
  64.     /* we don't know the interface it's going to go out, and */
  65.     /* the interfaces might have different callsigns.       */
  66.     n3hdr.source.call[0] = '\0' ;
  67.     n3hdr.dest = dest ;
  68.     n3hdr.ttl = nr_ttl ;
  69.  
  70.     /* Convert to a network format header.  This will be stripped */
  71.     /* back off in nr_route, but them's the breaks.               */
  72.     if ((tbp = htonnr3(&n3hdr)) == NULLBUF) {
  73.         free_p(bp) ;
  74.         return ;
  75.     }
  76.     append(tbp,bp) ;        /* append data to header */
  77.     nr_route(tbp) ;            /* pass off to level 3 routing code */
  78.  
  79. }
  80.  
  81. /* Figure out if a call is assigned to one of my net/rom
  82.  * interfaces.
  83.  */
  84. static int
  85. ismycall(addr)
  86. struct ax25_addr *addr ;
  87. {
  88.     register int i ;
  89.     int found = 0 ;
  90.     
  91.     for (i = 0 ; i < nr_numiface ; i++)
  92.         if (addreq((struct ax25_addr *)(nrifaces[i].interface->hwaddr),
  93.             addr)) {
  94.             found = 1 ;
  95.             break ;
  96.         }
  97.  
  98.     return found ;
  99. }
  100.  
  101.  
  102. /* Route net/rom network layer packets.
  103.  */
  104. nr_route(bp)
  105. struct mbuf *bp ;
  106. {
  107.     struct nr3hdr n3hdr ;
  108.     struct ax25_cb *axp, *find_ax25(), *open_ax25() ;
  109.     struct ax25 naxhdr ;
  110.     struct ax25_addr neighbor ;
  111.     struct mbuf *hbp, *pbp, *htonnr3() ;
  112.     extern int16 axwindow ;
  113.     void ax_incom() ;
  114.     register struct nrnbr_tab *np ;
  115.     register struct nrroute_tab *rp ;
  116.     register struct nr_bind *bindp, *find_best() ;
  117.     struct interface *interface ;
  118.     
  119.     if (ntohnr3(&n3hdr,&bp) == -1) {
  120.         free_p(bp) ;
  121.         return ;
  122.     }
  123.  
  124.     if (ismycall(&n3hdr.dest)) {
  125.         ip_route(bp,0) ;
  126.         return ;
  127.     }
  128.  
  129.     if ((rp = find_nrroute(&n3hdr.dest)) == NULLNRRTAB) {
  130.         /* no route, drop the packet */
  131.         free_p(bp) ;
  132.         return ;
  133.     }
  134.  
  135.     if ((bindp = find_best(rp->routes,1)) == NULLNRBIND) {
  136.         /* This shouldn't happen yet, but might if we add */
  137.         /* dead route detection */
  138.         free_p(bp) ;
  139.         return ;
  140.     }
  141.  
  142.     np = bindp->via ;
  143.     memcpy(neighbor.call,np->call,ALEN) ;
  144.     neighbor.ssid = np->call[ALEN] ;
  145.     interface = nrifaces[np->interface].interface ;
  146.  
  147.     /* Now check to see if the source call is null.  That is */
  148.     /* a signal from nr_send that the packet originates here, */
  149.     /* so we need to insert the callsign of the appropriate  */
  150.     /* interface */
  151.     if (n3hdr.source.call[0] == '\0')
  152.         memcpy(&n3hdr.source,interface->hwaddr,AXALEN) ;
  153.     
  154.     /* Make sure there is a connection to the neighbor */
  155.     if ((axp = find_ax25(&neighbor)) == NULLAX25 || axp->state != CONNECTED) {
  156.         /* Open a new connection or reinitialize old one */
  157.         /* hwaddr has been advanced to point to neighbor + digis */
  158.         atohax25(&naxhdr, np->call, (struct ax25_addr *)interface->hwaddr) ;
  159.         axp = open_ax25(&naxhdr, axwindow, ax_incom, NULLVFP, NULLVFP,
  160.                         interface,(char *)0) ;
  161.         if (axp == NULLAX25) {
  162.             free_p(bp) ;
  163.             return ;
  164.         }
  165.     }
  166.         
  167.     if (--n3hdr.ttl == 0) {    /* the packet's time to live is over! */
  168.         free_p(bp) ;
  169.         return ;
  170.     }
  171.  
  172.     /* allocate and fill PID mbuf */
  173.     if ((pbp = alloc_mbuf(1)) == NULLBUF) {
  174.         free_p(bp) ;
  175.         return ;
  176.     }
  177.     pbp->cnt = 1 ;
  178.     *pbp->data = (PID_FIRST | PID_LAST | PID_NETROM) ;
  179.  
  180.     /* now format network header */
  181.     if ((hbp = htonnr3(&n3hdr)) == NULLBUF) {
  182.         free_p(pbp) ;
  183.         free_p(bp) ;
  184.         return ;
  185.     }
  186.  
  187.     append(pbp,hbp) ;        /* append header to pid */
  188.     append(pbp,bp) ;        /* append data to header */
  189.     send_ax25(axp,pbp) ;    /* pass it off to ax25 code */
  190. }
  191.     
  192.  
  193. /* Perform a nodes broadcast on interface # ifno in the net/rom
  194.  * interface table.
  195.  */
  196.  
  197. nr_bcnodes(ifno)
  198. unsigned ifno ;
  199. {
  200.     struct mbuf *hbp, *dbp, *savehdr ;
  201.     struct nrroute_tab *rp ;
  202.     struct nrnbr_tab *np ;
  203.     struct nr_bind * bp ;
  204.     struct nr3dest nrdest ;
  205.     int i, didsend = 0, numdest = 0 ;
  206.     register char *cp ;
  207.     struct interface *axif = nrifaces[ifno].interface ;
  208.     struct nr_bind *find_best() ;
  209.     
  210.     /* prepare the header */
  211.     if ((hbp = alloc_mbuf(NR3NODEHL)) == NULLBUF)
  212.         return ;
  213.         
  214.     hbp->cnt = NR3NODEHL ;    
  215.     
  216.     *hbp->data = NR3NODESIG ;
  217.     memcpy(hbp->data+1,nrifaces[ifno].alias,ALEN) ;
  218.  
  219.     /* make a copy of the header in case we need to send more than */
  220.     /* one packet */
  221.     savehdr = copy_p(hbp,NR3NODEHL) ;
  222.  
  223.     /* now scan through the routing table, finding the best routes */
  224.     /* and their neighbors.  create destination subpackets and append */
  225.     /* them to the header */
  226.     for (i = 0 ; i < NRNUMCHAINS ; i++) {
  227.         for (rp = nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next) {
  228.             /* look for best, non-obsolescent route */
  229.             if ((bp = find_best(rp->routes,0)) == NULLNRBIND)
  230.                 continue ;    /* no non-obsolescent routes found */
  231.             if (bp->quality == 0)    /* this is a loopback route */
  232.                 continue ;            /* we never broadcast these */
  233.             np = bp->via ;
  234.             /* insert best neighbor */
  235.             memcpy(nrdest.neighbor.call,np->call,ALEN) ;
  236.             nrdest.neighbor.ssid = np->call[ALEN] ;
  237.             /* insert destination from route table */
  238.             nrdest.dest = rp->call ;
  239.             /* insert alias from route table */
  240.             strcpy(nrdest.alias,rp->alias) ;
  241.             /* insert quality from binding */
  242.             nrdest.quality = bp->quality ;
  243.             /* create a network format destination subpacket */
  244.             if ((dbp = htonnrdest(&nrdest)) == NULLBUF) {
  245.                 free_p(hbp) ;    /* drop the whole idea ... */
  246.                 free_p(savehdr) ;
  247.                 return ;
  248.             }
  249.             append(hbp,dbp) ;    /* append to header and others */
  250.             /* see if we have appended as many destinations */
  251.             /* as we can fit into a single broadcast.  If we */
  252.             /* have, go ahead and send them out. */
  253.             if (++numdest == NRDESTPERPACK) {    /* filled it up */
  254.                 didsend = 1 ;    /* indicate that we did broadcast */
  255.                 numdest = 0 ;    /* reset the destination counter */
  256.                 (*axif->output)(axif, (char *)&nr_nodebc, axif->hwaddr,
  257.                                  (PID_FIRST | PID_LAST | PID_NETROM),
  258.                                  hbp) ;    /* send it */
  259.                 hbp = copy_p(savehdr,NR3NODEHL) ;    /* new header */
  260.             }
  261.         }
  262.     }
  263.  
  264.     /* Now, here is something totally weird.  If our interfaces */
  265.     /* have different callsigns than this one, advertise a very */
  266.     /* high quality route to them.  Is this a good idea?  I don't */
  267.     /* know.  However, it allows us to simulate a bunch of net/roms */
  268.     /* hooked together with a diode matrix coupler. */
  269.     for (i = 0 ; i < nr_numiface ; i++) {
  270.         if (i == ifno)
  271.             continue ;        /* don't bother with ours */
  272.         cp = nrifaces[i].interface->hwaddr ;
  273.         if (!addreq((struct ax25_addr *)axif->hwaddr,cp)) {
  274.             /* both destination and neighbor address */
  275.             memcpy(&nrdest.dest,cp,AXALEN) ;
  276.             memcpy(&nrdest.neighbor,cp,AXALEN) ;
  277.             /* alias of the interface */
  278.             strcpy(nrdest.alias,nrifaces[i].alias) ;
  279.             /* and the very highest quality */
  280.             nrdest.quality = 255 ;
  281.             /* create a network format destination subpacket */
  282.             if ((dbp = htonnrdest(&nrdest)) == NULLBUF) {
  283.                 free_p(hbp) ;    /* drop the whole idea ... */
  284.                 free_p(savehdr) ;
  285.                 return ;
  286.             }
  287.             append(hbp,dbp) ;    /* append to header and others */
  288.             if (++numdest == NRDESTPERPACK) {    /* filled it up */
  289.                 didsend = 1 ;    /* indicate that we did broadcast */
  290.                 numdest = 0 ;    /* reset the destination counter */
  291.                 (*axif->output)(axif, (char *)&nr_nodebc, axif->hwaddr,
  292.                                  (PID_FIRST | PID_LAST | PID_NETROM),
  293.                                  hbp) ;    /* send it */
  294.                 hbp = copy_p(savehdr,NR3NODEHL) ;    /* new header */
  295.             }
  296.         }
  297.     }
  298.             
  299.     /* If we have a partly filled packet left over, or we never */
  300.     /* sent one at all, we broadcast: */
  301.     if (!didsend || numdest > 0)
  302.         (*axif->output)(axif, (char *)&nr_nodebc, axif->hwaddr,
  303.                         (PID_FIRST | PID_LAST | PID_NETROM), hbp) ;
  304.  
  305.     free_p(savehdr) ;    /* free the header copy */
  306. }
  307.  
  308.  
  309. /* initialize fake arp entry for netrom */
  310. nr3arp()
  311. {
  312.     int psax25(), setpath() ;
  313.  
  314.     arp_init(ARP_NETROM,AXALEN,0,0,NULLCHAR,psax25,setpath) ;
  315. }
  316.  
  317. /* attach the net/rom interface.  no parms for now. */
  318. nr_attach(argc,argv)
  319. int argc ;
  320. char *argv[] ;
  321. {
  322.     if (nr_interface != (struct interface *)0) {
  323.         printf("netrom interface already attached\n") ;
  324.         return -1 ;
  325.     }
  326.  
  327.     nr3arp() ;
  328.     
  329.     nr_interface = (struct interface *)calloc(1,sizeof(struct interface)) ;
  330.     nr_interface->name = "netrom" ;
  331.     nr_interface->mtu = NR3DLEN ;
  332.     nr_interface->send = nr_send ;
  333.     nr_interface->next = ifaces ;
  334.     ifaces = nr_interface ;
  335.     return 0 ;
  336. }
  337.  
  338. /* This function checks an ax.25 address and interface number against
  339.  * the filter table and mode, and returns 1 if the address is to be
  340.  * accepted, and 0 if it is to be filtered out.
  341.  */
  342. static int
  343. accept_bc(addr,ifnum)
  344. struct ax25_addr *addr ;
  345. unsigned ifnum ;
  346. {
  347.     struct nrnf_tab *fp ;
  348.  
  349.     if (nr_nfmode == NRNF_NOFILTER)        /* no filtering in effect */
  350.         return 1 ;
  351.  
  352.     fp = find_nrnf(addr,ifnum) ;        /* look it up */
  353.     
  354.     if ((fp != NULLNRNFTAB && nr_nfmode == NRNF_ACCEPT)
  355.         || (fp == NULLNRNFTAB && nr_nfmode == NRNF_REJECT))
  356.         return 1 ;
  357.     else
  358.         return 0 ;
  359. }
  360.  
  361.  
  362. /* receive and process node broadcasts. */
  363. nr_nodercv(interface,source,bp)
  364. struct interface *interface ;
  365. struct ax25_addr *source ;
  366. struct mbuf *bp ;
  367. {
  368.     register int ifnum ;
  369.     char bcalias[7] ;
  370.     char buf[16] ;
  371.     struct nr3dest ds ;
  372.     char sbuf[AXALEN*3] ;
  373.     
  374.     /* First, see if this is even a net/rom interface: */
  375.     for (ifnum = 0 ; ifnum < nr_numiface ; ifnum++)
  376.         if (interface == nrifaces[ifnum].interface)
  377.             break ;
  378.             
  379.     if (ifnum == nr_numiface) {    /* not in the interface table */
  380.         free_p(bp) ;
  381.         return ;
  382.     }
  383.  
  384.     if (!accept_bc(source,ifnum)) {    /* check against filter */
  385.         free_p(bp) ;
  386.         return ;
  387.     }
  388.     
  389.     /* See if it has a routing broadcast signature: */
  390.     if (uchar(pullchar(&bp)) != NR3NODESIG) {
  391.         free_p(bp) ;
  392.         return ;
  393.     }
  394.  
  395.     /* now try to get the alias */
  396.     if (pullup(&bp,bcalias,ALEN) < ALEN) {
  397.         free_p(bp) ;
  398.         return ;
  399.     }
  400.  
  401.     bcalias[ALEN] = '\0' ;        /* null terminate */
  402.  
  403.     /* copy source address and convert to arp format */
  404.     memcpy(sbuf,source->call,ALEN) ;
  405.     sbuf[ALEN] = (source->ssid | E) ;    /* terminate */
  406.     
  407.     /* enter the neighbor into our routing table */
  408.     if (nr_routeadd(bcalias,source,ifnum,nrifaces[ifnum].quality,
  409.                     sbuf, 0) == -1) {
  410.         free_p(bp) ;
  411.         return ;
  412.     }
  413.     
  414.     /* we've digested the header; now digest the actual */
  415.     /* routing information */
  416.     while (ntohnrdest(&ds,&bp) != -1) {
  417.         /* ignore routes to me! */
  418.         if (ismycall(&ds.dest))
  419.             continue ;
  420.         /* ignore routes below the minimum quality threshhold */
  421.         if (ds.quality < nr_autofloor)
  422.             continue ;
  423.         /* set loopback paths to 0 quality */
  424.         if (ismycall(&ds.neighbor))
  425.             ds.quality = 0 ;
  426.         else
  427.             ds.quality = ((ds.quality * nrifaces[ifnum].quality + 128)
  428.                           / 256) & 0xff ;
  429.         if (nr_routeadd(ds.alias,&ds.dest,ifnum,ds.quality,sbuf,0)
  430.             == -1)
  431.             break ;
  432.     }
  433.             
  434.     free_p(bp) ;    /* This will free the mbuf if anything fails above */
  435. }
  436.  
  437.  
  438. /* The following are utilities for manipulating the routing table */
  439.  
  440. /* hash function for callsigns.  Look familiar? */
  441. int16
  442. nrhash(s)
  443. struct ax25_addr *s ;
  444. {
  445.     register char x ;
  446.     register int i ;
  447.     register char *cp ;
  448.  
  449.     x = 0 ;
  450.     cp = s->call ;
  451.     for (i = ALEN ; i !=0 ; i--)
  452.         x ^= *cp++ & 0xfe ;
  453.     x ^= s->ssid & SSID ;
  454.     return uchar(x) % NRNUMCHAINS ;
  455. }
  456.  
  457. /* Find a neighbor table entry.  Neighbors are determined by
  458.  * their callsign and the interface number.  This takes care
  459.  * of the case where the same switch or hosts uses the same
  460.  * callsign on two different channels.  This isn't done by
  461.  * net/rom, but it might be done by stations running *our*
  462.  * software.
  463.  */
  464. struct nrnbr_tab *
  465. find_nrnbr(addr,ifnum)
  466. register struct ax25_addr *addr ;
  467. unsigned ifnum ;
  468. {
  469.     int16 hashval ;
  470.     register struct nrnbr_tab *np ;
  471.     char i_state ;
  472.     struct ax25_addr ncall ;
  473.  
  474.     /* Find appropriate hash chain */
  475.     hashval = nrhash(addr) ;
  476.  
  477.     /* search hash chain */
  478.     i_state = disable() ;
  479.     for (np = nrnbr_tab[hashval] ; np != NULLNTAB ; np = np->next) {
  480.         memcpy(ncall.call,np->call,ALEN) ;    /* convert first in */
  481.         ncall.ssid = np->call[ALEN] ; /* list to ax25 address format */
  482.         if (addreq(&ncall,addr) && np->interface == ifnum) {
  483.             restore(i_state) ;
  484.             return np ;
  485.         }
  486.     }
  487.     restore(i_state) ;
  488.     return NULLNTAB ;
  489. }
  490.  
  491.  
  492. /* Find a route table entry */
  493. struct nrroute_tab *
  494. find_nrroute(addr)
  495. register struct ax25_addr *addr ;
  496. {
  497.     int16 hashval ;
  498.     register struct nrroute_tab *rp ;
  499.     char i_state ;
  500.  
  501.     /* Find appropriate hash chain */
  502.     hashval = nrhash(addr) ;
  503.  
  504.     /* search hash chain */
  505.     i_state = disable() ;
  506.     for (rp = nrroute_tab[hashval] ; rp != NULLNRRTAB ; rp = rp->next) {
  507.         if (addreq(&rp->call,addr)) {
  508.             restore(i_state) ;
  509.             return rp ;
  510.         }
  511.     }
  512.     restore(i_state) ;
  513.     return NULLNRRTAB ;
  514. }
  515.  
  516.  
  517. /* Find a binding in a list by its neighbor structure's address */
  518. struct nr_bind *
  519. find_binding(list,neighbor)
  520. struct nr_bind *list ;
  521. register struct nrnbr_tab *neighbor ;
  522. {
  523.     register struct nr_bind *bp ;
  524.  
  525.     for(bp = list ; bp != NULLNRBIND ; bp = bp->next)
  526.         if (bp->via == neighbor)
  527.             return bp ;
  528.  
  529.     return NULLNRBIND ;
  530. }
  531.  
  532. /* Find the worst quality non-permanent binding in a list */
  533. static
  534. struct nr_bind *
  535. find_worst(list)
  536. struct nr_bind *list ;
  537. {
  538.     register struct nr_bind *bp ;
  539.     struct nr_bind *worst = NULLNRBIND ;
  540.     unsigned minqual = 1000 ;     /* infinity */
  541.  
  542.     for (bp = list ; bp != NULLNRBIND ; bp = bp->next)
  543.         if (!(bp->flags & NRB_PERMANENT) && bp->quality < minqual) {
  544.             worst = bp ;
  545.             minqual = bp->quality ;
  546.         }
  547.  
  548.     return worst ;
  549. }
  550.  
  551. /* Find the best binding of any sort in a list.  If obso is 1,
  552.  * include entries below the obsolescence threshhold in the
  553.  * search (used when this is called for routing broadcasts).
  554.  * If it is 0, routes below the threshhold are treated as
  555.  * though they don't exist.
  556.  */
  557. static
  558. struct nr_bind *
  559. find_best(list,obso)
  560. struct nr_bind *list ;
  561. unsigned obso ;
  562. {
  563.     register struct nr_bind *bp ;
  564.     struct nr_bind *best = NULLNRBIND ;
  565.     int maxqual = -1 ;    /* negative infinity */
  566.  
  567.     for (bp = list ; bp != NULLNRBIND ; bp = bp->next)
  568.         if ((int)bp->quality > maxqual)
  569.             if (obso || bp->obsocnt >= obso_minbc) {
  570.                 best = bp ;
  571.                 maxqual = bp->quality ;
  572.             }
  573.  
  574.     return best ;
  575. }
  576.  
  577. /* Add a route to the net/rom routing table */
  578. nr_routeadd(alias,dest,ifnum,quality,neighbor,permanent)
  579. char *alias ;                /* net/rom node alias, blank-padded and */
  580.                             /* null-terminated */
  581. struct ax25_addr *dest ;    /* destination node callsign */
  582. unsigned ifnum ;            /* net/rom interface number */
  583. unsigned quality ;            /* route quality */
  584. char *neighbor ;            /* neighbor node + 2 digis (max) in arp format */
  585. unsigned permanent ;        /* 1 if route is permanent (hand-entered) */
  586. {
  587.     struct nrroute_tab *rp ;
  588.     struct nr_bind *bp ;
  589.     struct nrnbr_tab *np ;
  590.     int16 rhash, nhash ;
  591.     struct ax25_addr ncall ;
  592.  
  593.     /* See if a routing table entry exists for this destination */
  594.     if ((rp = find_nrroute(dest)) == NULLNRRTAB) {
  595.         if ((rp =
  596.              (struct nrroute_tab *)calloc(1,sizeof(struct nrroute_tab)))
  597.             == NULLNRRTAB)
  598.             return -1 ;
  599.         else {            /* create a new route table entry */
  600.             strncpy(rp->alias,alias,6) ;
  601.             rp->call = *dest ;
  602.             rhash = nrhash(dest) ;
  603.             rp->next = nrroute_tab[rhash] ;
  604.             if (rp->next != NULLNRRTAB)
  605.                 rp->next->prev = rp ;
  606.             nrroute_tab[rhash] = rp ;    /* link at head of hash chain */
  607.         }
  608.     }
  609.  
  610.     /* See if an entry exists for this neighbor */
  611.     memcpy(ncall.call,neighbor,ALEN) ;    /* no digis included */
  612.     ncall.ssid = neighbor[ALEN] ;
  613.     if ((np = find_nrnbr(&ncall,ifnum)) == NULLNTAB) {
  614.         if ((np =
  615.              (struct nrnbr_tab *)calloc(1,sizeof(struct nrnbr_tab)))
  616.              == NULLNTAB) {
  617.             if (rp->num_routes == 0) {    /* we just added to table */
  618.                 nrroute_tab[rhash] = rp->next ;
  619.                 free(rp) ;                /* so get rid of it */
  620.             }
  621.             return -1 ;
  622.         }
  623.         else {        /* create a new neighbor entry */
  624.             memcpy(np->call,neighbor,3 * AXALEN) ;
  625.             np->interface = ifnum ;
  626.             nhash = nrhash(&ncall) ;
  627.             np->next = nrnbr_tab[nhash] ;
  628.             if (np->next != NULLNTAB)
  629.                 np->next->prev = np ;
  630.             nrnbr_tab[nhash] = np ;
  631.         }
  632.     }
  633.     else if (permanent) {        /* force this path to the neighbor */
  634.         memcpy(np->call,neighbor,3 * AXALEN) ;
  635.     }
  636.         
  637.     /* See if there is a binding between the dest and neighbor */
  638.     if ((bp = find_binding(rp->routes,np)) == NULLNRBIND) {
  639.         if ((bp =
  640.              (struct nr_bind *)calloc(1,sizeof(struct nr_bind)))
  641.             == NULLNRBIND) {
  642.             if (rp->num_routes == 0) {    /* we just added to table */
  643.                 nrroute_tab[rhash] = rp->next ;
  644.                 free(rp) ;                /* so get rid of it */
  645.             }
  646.             if (np->refcnt == 0) {        /* we just added it */
  647.                 nrnbr_tab[nhash] = np->next ;
  648.                 free(np) ;
  649.             }
  650.             return -1 ;
  651.         }
  652.         else {        /* create a new binding and link it in */
  653.             bp->via = np ;    /* goes via this neighbor */
  654.             bp->next = rp->routes ;    /* link into binding chain */
  655.             if (bp->next != NULLNRBIND)
  656.                 bp->next->prev = bp ;
  657.             rp->routes = bp ;
  658.             rp->num_routes++ ;    /* bump route count */
  659.             np->refcnt++ ;        /* bump neighbor ref count */
  660.             bp->quality = quality ;
  661.             bp->obsocnt = obso_init ;    /* use initial value */
  662.             if (permanent)
  663.                 bp->flags |= NRB_PERMANENT ;
  664.         }
  665.     }
  666.     /* Don't allow broadcasts to modify permanent entries */
  667.     else if (permanent || !(bp->flags & NRB_PERMANENT)) {
  668.         bp->quality = quality ;
  669.         bp->obsocnt = obso_init ;
  670.         if (permanent)                    
  671.             bp->flags |= NRB_PERMANENT ;    /* make it permanent */
  672.     }
  673.  
  674.     /* Now, check to see if we have too many bindings, and drop */
  675.     /* the worst if we do */
  676.     if (rp->num_routes > nr_maxroutes) {
  677.         /* since find_worst never returns permanent entries, the */
  678.         /* limitation on number of routes is circumvented for    */
  679.         /* permanent routes */
  680.         if ((bp = find_worst(rp->routes)) != NULLNRBIND) {
  681.             memcpy(ncall.call,bp->via->call,ALEN) ;
  682.             ncall.ssid = bp->via->call[ALEN] ;
  683.             nr_routedrop(dest,&ncall,bp->via->interface) ;
  684.         }
  685.     }
  686.  
  687.     return 0 ;
  688. }
  689.  
  690.  
  691. /* Drop a route to dest via neighbor */
  692. nr_routedrop(dest,neighbor,ifnum)
  693. struct ax25_addr *dest, *neighbor ;
  694. unsigned ifnum ;
  695. {
  696.     register struct nrroute_tab *rp ;
  697.     register struct nrnbr_tab *np ;
  698.     register struct nr_bind *bp ;
  699.  
  700.     if ((rp = find_nrroute(dest)) == NULLNRRTAB)
  701.         return -1 ;
  702.  
  703.     if ((np = find_nrnbr(neighbor,ifnum)) == NULLNTAB)
  704.         return -1 ;
  705.  
  706.     if ((bp = find_binding(rp->routes,np)) == NULLNRBIND)
  707.         return -1 ;
  708.  
  709.     /* drop the binding first */
  710.     if (bp->next != NULLNRBIND)
  711.         bp->next->prev = bp->prev ;
  712.     if (bp->prev != NULLNRBIND)
  713.         bp->prev->next = bp->next ;
  714.     else
  715.         rp->routes = bp->next ;
  716.  
  717.     free(bp) ;
  718.     rp->num_routes-- ;        /* decrement the number of bindings */
  719.     np->refcnt-- ;            /* and the number of neighbor references */
  720.     
  721.     /* now see if we should drop the route table entry */
  722.     if (rp->num_routes == 0) {
  723.         if (rp->next != NULLNRRTAB)
  724.             rp->next->prev = rp->prev ;
  725.         if (rp->prev != NULLNRRTAB)
  726.             rp->prev->next = rp->next ;
  727.         else
  728.             nrroute_tab[nrhash(dest)] = rp->next ;
  729.  
  730.         free(rp) ;
  731.     }
  732.  
  733.     /* and check to see if this neighbor can be dropped */
  734.     if (np->refcnt == 0) {
  735.         if (np->next != NULLNTAB)
  736.             np->next->prev = np->prev ;
  737.         if (np->prev != NULLNTAB)
  738.             np->prev->next = np->next ;
  739.         else
  740.             nrnbr_tab[nrhash(neighbor)] = np->next ;
  741.  
  742.         free(np) ;
  743.     }
  744.     
  745.     return 0 ;
  746. }
  747.  
  748. /* Find the best neighbor for destination dest, in arp format */
  749. char *
  750. nr_getroute(dest)
  751. struct ax25_addr *dest ;
  752. {
  753.     register struct nrroute_tab *rp ;
  754.     register struct nr_bind *bp ;
  755.  
  756.     if ((rp = find_nrroute(dest)) == NULLNRRTAB)
  757.         return NULLCHAR ;
  758.  
  759.     if ((bp = find_best(rp->routes)) == NULLNRBIND)    /* shouldn't happen! */
  760.         return NULLCHAR ;
  761.  
  762.     return bp->via->call ;
  763. }
  764.  
  765. /* Find an entry in the filter table */
  766. struct nrnf_tab *
  767. find_nrnf(addr,ifnum)
  768. register struct ax25_addr *addr ;
  769. unsigned ifnum ;
  770. {
  771.     int16 hashval ;
  772.     register struct nrnf_tab *fp ;
  773.  
  774.     /* Find appropriate hash chain */
  775.     hashval = nrhash(addr) ;
  776.  
  777.     /* search hash chain */
  778.     for (fp = nrnf_tab[hashval] ; fp != NULLNRNFTAB ; fp = fp->next) {
  779.         if (addreq(&fp->neighbor,addr) && fp->interface == ifnum) {
  780.             return fp ;
  781.         }
  782.     }
  783.  
  784.     return NULLNRNFTAB ;
  785. }
  786.  
  787. /* Add an entry to the filter table.  Return 0 on success,
  788.  * -1 on failure
  789.  */
  790. int
  791. nr_nfadd(addr,ifnum)
  792. struct ax25_addr *addr ;
  793. unsigned ifnum ;
  794. {
  795.     struct nrnf_tab *fp ;
  796.     int16 hashval ;
  797.     
  798.     if (find_nrnf(addr,ifnum) != NULLNRNFTAB)
  799.         return 0 ;    /* already there; it's a no-op */
  800.  
  801.     if ((fp = (struct nrnf_tab *)calloc(1,sizeof(struct nrnf_tab)))
  802.         == NULLNRNFTAB)
  803.         return -1 ;    /* no storage */
  804.  
  805.     hashval = nrhash(addr) ;
  806.     fp->neighbor = *addr ;
  807.     fp->interface = ifnum ;
  808.     fp->next = nrnf_tab[hashval] ;
  809.     if (fp->next != NULLNRNFTAB)
  810.         fp->next->prev = fp ;
  811.     nrnf_tab[hashval] = fp ;
  812.  
  813.     return 0 ;
  814. }
  815.  
  816. /* Drop a neighbor from the filter table.  Returns 0 on success, -1
  817.  * on failure.
  818.  */
  819. int
  820. nr_nfdrop(addr,ifnum)
  821. struct ax25_addr *addr ;
  822. unsigned ifnum ;
  823. {
  824.     struct nrnf_tab *fp ;
  825.  
  826.     if ((fp = find_nrnf(addr,ifnum)) == NULLNRNFTAB)
  827.         return -1 ;    /* not in the table */
  828.  
  829.     if (fp->next != NULLNRNFTAB)
  830.         fp->next->prev = fp->prev ;
  831.     if (fp->prev != NULLNRNFTAB)
  832.         fp->prev->next = fp->next ;
  833.     else
  834.         nrnf_tab[nrhash(addr)] = fp->next ;
  835.  
  836.     free(fp) ;
  837.  
  838.     return 0 ;
  839. }
  840.